<?php
// +---------------------------------------------------------------------+
// | OneBase    | [ WE CAN DO IT JUST THINK ]                            |
// +---------------------------------------------------------------------+
// | Licensed   | http://www.apache.org/licenses/LICENSE-2.0 )           |
// +---------------------------------------------------------------------+
// | Author     | 王勇程 <laughskydragon@qq.com>                         |
// +---------------------------------------------------------------------+
// | Repository | https://gitee.com/Bigotry/OneBase                      |
// +---------------------------------------------------------------------+

namespace app\common\controller;

use think\App;
use think\Request;
use think\facade\Event;
use think\facade\View;
use think\exception\HttpResponseException;
use think\Response; // 确保引入 Response 门面

/**
 * 系统通用控制器基类
 */
class ControllerBase
{
    
    /**
     * Request实例
     * @var Request
     */
    protected $request;
    
    /**
     * 应用实例
     * @var App
     */
    protected $app;
    
    // 请求参数
    protected $param;
    
    /**
     * 构造方法
     * @param App     $app     应用对象
     * @param Request $request 请求对象
     */
    public function __construct(App $app, Request $request)
    {
        $this->app     = $app;
        $this->request = $request;
        
        // 控制器初始化
        $this->initialize();
    }
    
    /**
     * 初始化
     */
    protected function initialize()
    {
        
        // 初始化请求信息
        $this->initRequestInfo();
        
        // 初始化全局静态资源
        $this->initCommonStatic();
        
        // 初始化响应类型
        $this->initResponseType();
        
        // 通用控制器事件
        Event::trigger('ControllerCommonBase', $this->request);
    }
    
    /**
     * 初始化请求信息
     */
    private function initRequestInfo()
    {
        
        defined('IS_POST')          or define('IS_POST',         $this->request->isPost());
        defined('IS_GET')           or define('IS_GET',          $this->request->isGet());
        defined('IS_AJAX')          or define('IS_AJAX',         $this->request->isAjax());
        defined('IS_PJAX')          or define('IS_PJAX',         $this->request->isPjax());
        defined('IS_MOBILE')        or define('IS_MOBILE',       $this->request->isMobile());
        defined('MODULE_NAME')      or define('MODULE_NAME',     strtolower($this->app->http->getName()));
        defined('CONTROLLER_NAME')  or define('CONTROLLER_NAME', strtolower($this->request->controller()));
        defined('ACTION_NAME')      or define('ACTION_NAME',     strtolower($this->request->action()));
        defined('URL')              or define('URL',             CONTROLLER_NAME . SYS_DS_PROS . ACTION_NAME);
        defined('URL_TRUE')         or define('URL_TRUE',        $this->request->url(true));
        defined('DOMAIN')           or define('DOMAIN',          $this->request->domain());
        defined('URL_ROOT')         or define('URL_ROOT',        $this->request->root());

        $this->param = $this->request->param();
    }
    
    /**
     * 初始化响应类型
     */
    private function initResponseType()
    {
        
        IS_AJAX && !IS_PJAX  ? config('default_ajax_return', null, 'json') : config('default_ajax_return', null, 'html');
    }
    
    /**
     * 系统通用跳转
     */
    final protected function jump($jump_type = null, $message = null, $url = null)
    {
        
        $data = is_array($jump_type) ? $this->parseJumpArray($jump_type) : $this->parseJumpArray([$jump_type, $message, $url]);
        
        $success  = RESULT_SUCCESS;
        $error    = RESULT_ERROR;
        $redirect = RESULT_REDIRECT;
        
        $u = 'url';
        $m = 'message';
        
        !empty($data[$u]) && $data[$u] = DOMAIN . $data[$u];
        
        switch ($data['jump_type'])
        {
            case $success  : $this->$success($data[$m], $data[$u]); break;
            case $error    : $this->$error($data[$m], $data[$u]);   break;
            case $redirect : $this->$redirect($data[$u]);           break;
            default        : throw new \Exception('系统跳转失败:' . $data[$u]);
        }
    }
    
    /**
     * 解析跳转数组
     */
    final protected function  parseJumpArray($jump_array = [])
    {
        
        !isset($jump_array[2]) && $jump_array[2] = null;
       
        return ['jump_type' => $jump_array[0], 'message' => $jump_array[1], 'url' => $jump_array[2]];
    }
    
    /**
     * 初始化全局静态资源
     */
    final protected function initCommonStatic()
    {
        
        $this->assign('loading_icon', config('loading_icon'));
        
        $this->assign('pjax_mode',    config('pjax_mode'));
        
        $this->assign('static_root',  DOMAIN . dirname(URL_ROOT) . SYS_DS_PROS . SYS_STATIC_DIR_NAME . SYS_DS_PROS);
    }
    
    /**
     * 模板变量赋值
     * @param mixed $name  要显示的模板变量
     * @param mixed $value 变量的值
     * @return $this
     */
    protected function assign($name, $value = '')
    {
        View::assign($name, $value);
        
        return $this;
    }
    
    /**
     * 渲染模板输出
     * @param string $template 模板文件
     * @param array  $vars     模板变量
     * @return string
     */
    protected function fetch(string $template = '', array $vars = [])
    {
        return View::fetch($template, $vars);
    }
    
    /**
     * 操作成功跳转的快捷方法
     * @param mixed $msg 提示信息
     * @param string $url 跳转的URL地址
     * @param mixed $data 返回的数据
     * @param integer $wait 跳转等待时间
     * @param array $header 发送的Header信息
     * @return void
     */
    protected function success($msg = '', string $url = null, $data = '', int $wait = 3, array $header = [])
    {
        if (is_null($url) && isset($_SERVER["HTTP_REFERER"])) {
            $url = $_SERVER["HTTP_REFERER"];
        } elseif ($url) {
            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url);
        }
        
        $result = [
            'code' => 1,
            'msg'  => $msg,
            'data' => $data,
            'url'  => $url,
            'wait' => $wait,
        ];
        
        $type = $this->getResponseType();
        if ($type == 'html'){
            // 关键修复：在 TP8 下从 view 组读取跳转模板，避免拿到数组
            $tmpl = config('view.dispatch_success_tmpl');
            // 兜底：若读取失败或类型不为字符串，使用框架内置模板
            if (!is_string($tmpl) || $tmpl === '') {
                $tmpl = app()->getThinkPath() . 'tpl/dispatch_jump.tpl';
            }
            // 将 View::fetch 返回的字符串封装为 Response 对象
            $response = Response::create(View::fetch($tmpl, $result), 'html');
        } else {
            $response = json($result);
        }
        
        throw new \think\exception\HttpResponseException($response);
    }
    
    /**
     * 操作错误跳转的快捷方法
     * @param mixed $msg 提示信息
     * @param string $url 跳转的URL地址
     * @param mixed $data 返回的数据
     * @param integer $wait 跳转等待时间
     * @param array $header 发送的Header信息
     * @return void
     */
    protected function error($msg = '', string $url = null, $data = '', int $wait = 3, array $header = [])
    {
        if (is_null($url)) {
            $url = $this->request->isAjax() ? '' : 'javascript:history.back(-1);';
        } elseif ($url) {
            $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : $this->app->route->buildUrl($url);
        }
        
        $result = [
            'code' => 0,
            'msg'  => $msg,
            'data' => $data,
            'url'  => $url,
            'wait' => $wait,
        ];
        
        $type = $this->getResponseType();
        if ($type == 'html'){
            // 关键修复：在 TP8 下从 view 组读取跳转模板，避免拿到数组
            $tmpl = config('view.dispatch_error_tmpl');
            // 兜底：若读取失败或类型不为字符串，使用框架内置模板
            if (!is_string($tmpl) || $tmpl === '') {
                $tmpl = app()->getThinkPath() . 'tpl/dispatch_jump.tpl';
            }
            // 将 View::fetch 返回的字符串封装为 Response 对象
            $response = Response::create(View::fetch($tmpl, $result), 'html');
        } else {
            $response = json($result);
        }
        
        throw new \think\exception\HttpResponseException($response);
    }
    
    /**
     * URL重定向
     * @param string $url 跳转的URL表达式
     * @param integer $code http code
     * @return void
     */
    protected function redirect($url, $code = 302)
    {
        // 标准化URL：当为字符串且非绝对地址时，使用路由生成器补全当前应用前缀（如 /admin）
        if (is_string($url)) {
            $isAbsolute = (strpos($url, '://') !== false) || (isset($url[0]) && $url[0] === '/');
            if (!$isAbsolute) {
                $url = $this->app->route->buildUrl($url);
            }
        }

        $response = redirect($url, $code);
        throw new \think\exception\HttpResponseException($response);
    }
    
    /**
     * 获取当前的response 输出类型
     * @return string
     */
    protected function getResponseType()
    {
        // 仅读取配置，未取到时回退为 'json'，避免两参写入带来的副作用
        return $this->request->isAjax() ? config('default_ajax_return', null, 'json') : 'html';
    }
    
    /**
     * 获取逻辑层实例
     */
    public function __get($name)
    {
        
        !str_prefix($name, LAYER_LOGIC_NAME) && throw new \Exception('逻辑层引用需前缀:' . LAYER_LOGIC_NAME);
        
        return model(sr($name, LAYER_LOGIC_NAME), LAYER_LOGIC_NAME);
    }
}
